package com.author.document.style;

import java.awt.Color;
import java.util.Hashtable;

import javax.swing.text.AttributeSet;
import javax.swing.text.Element;
import javax.swing.text.StyleConstants;

import com.author.document.model.ExtendedDocument;
import com.author.surface.BackgroundColorButton;
import com.author.surface.CustomSlider;
import com.author.surface.ForegroundColorButton;
import com.author.surface.LineSpacingButtonGroup;
import com.author.surface.Surface;
import com.author.surface.ToolPanel;
import com.author.surface.UIupdater;

public final class StyleObserver {
	/* Table that maps a style attribute property to its current value */
	private Hashtable<Object, Object>	styleValuesTable	= new Hashtable<Object, Object>();

	/* The update to surface UI will happen through the UIupdater */
	private static final UIupdater		UIupdate			= UIupdater
																	.getUIupdater();

	/**
	 * The Text Pane will be responsible for forwarding the current style at the
	 * given caret position to the StyleObserver. The Text Pane will do that by
	 * sending an element to the Style Observer for the current Caret position.
	 */
	public void setCharacterStyle(Element e) {
		if (e == null) {
			return;
		}

		updateCharacterStyleValues(e); // update style values table

		/*
		 * Send the list of UI changes to the UIupdater so that the changes
		 * become visible in the tool panel buttons
		 */
		UIupdate.update(styleValuesTable);
	}

	private void updateCharacterStyleValues(Element elem) {
		AttributeSet set = elem.getAttributes();

		/*
		 * Get all properties and their corresponding current values and update
		 * the style values table
		 */
		if (styleValuesTable.contains(StyleConstants.FontSize)) {
			int value = (Integer) styleValuesTable.get(StyleConstants.FontSize);
			int value2 = (Integer) set.getAttribute(StyleConstants.FontSize);

			if (value != value2) {
				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(StyleConstants.FontSize);
				styleValuesTable.put(StyleConstants.FontSize, value2);
			}
		} else {
			Integer value = (Integer) set.getAttribute(StyleConstants.FontSize);
			if (value == null) {
				value = DefaultStyleConstant
						.getFontSizeForStyleName(DefaultStyleConstant.NORMAL_STYLE);
			}
			styleValuesTable.put(StyleConstants.FontSize, value);
		}

		if (styleValuesTable.contains(StyleConstants.Bold)) {
			boolean value = (Boolean) styleValuesTable.get(StyleConstants.Bold);
			boolean value2 = (Boolean) set.getAttribute(StyleConstants.Bold);

			if (value != value2) {
				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(StyleConstants.Bold);
				styleValuesTable.put(StyleConstants.Bold, value2);
			}
		} else {
			Boolean value = (Boolean) set.getAttribute(StyleConstants.Bold);
			if (value != null) {
				styleValuesTable.put(StyleConstants.Bold, value);
			} else {
				styleValuesTable.put(StyleConstants.Bold, false);
			}
		}

		if (styleValuesTable.contains(StyleConstants.Italic)) {
			boolean value = (Boolean) styleValuesTable
					.get(StyleConstants.Italic);
			boolean value2 = (Boolean) set.getAttribute(StyleConstants.Italic);

			if (value != value2) {
				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(StyleConstants.Italic);
				styleValuesTable.put(StyleConstants.Italic, value2);
			}
		} else {
			Boolean value = (Boolean) set.getAttribute(StyleConstants.Italic);
			if (value != null) {
				styleValuesTable.put(StyleConstants.Italic, value);
			} else {
				styleValuesTable.put(StyleConstants.Italic, false);
			}
		}

		if (styleValuesTable.contains(StyleConstants.Underline)) {
			boolean value = (Boolean) styleValuesTable
					.get(StyleConstants.Underline);
			boolean value2 = (Boolean) set
					.getAttribute(StyleConstants.Underline);

			if (value != value2) {
				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(StyleConstants.Underline);
				styleValuesTable.put(StyleConstants.Underline, value2);
			}
		} else {
			Boolean value = (Boolean) set
					.getAttribute(StyleConstants.Underline);
			if (value != null) {
				styleValuesTable.put(StyleConstants.Underline, value);
			} else {
				styleValuesTable.put(StyleConstants.Underline, false);
			}
		}

		if (styleValuesTable.contains(StyleConstants.Superscript)) {
			boolean value = (Boolean) styleValuesTable
					.get(StyleConstants.Superscript);
			boolean value2 = (Boolean) set
					.getAttribute(StyleConstants.Superscript);

			if (value != value2) {
				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(StyleConstants.Superscript);
				styleValuesTable.put(StyleConstants.Superscript, value2);
			}
		} else {
			Boolean value = (Boolean) set
					.getAttribute(StyleConstants.Superscript);
			if (value != null) {
				styleValuesTable.put(StyleConstants.Superscript, value);
			} else {
				styleValuesTable.put(StyleConstants.Superscript, false);
			}
		}

		if (styleValuesTable.contains(StyleConstants.Subscript)) {
			boolean value = (Boolean) styleValuesTable
					.get(StyleConstants.Subscript);
			boolean value2 = (Boolean) set
					.getAttribute(StyleConstants.Subscript);

			if (value != value2) {
				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(StyleConstants.Subscript);
				styleValuesTable.put(StyleConstants.Subscript, value2);
			}
		} else {
			Boolean value = (Boolean) set
					.getAttribute(StyleConstants.Subscript);
			if (value != null) {
				styleValuesTable.put(StyleConstants.Subscript, value);
			} else {
				styleValuesTable.put(StyleConstants.Subscript, false);
			}
		}

		if (styleValuesTable.get(StyleConstants.Alignment) == null) {
			styleValuesTable.put(StyleConstants.Alignment,
					StyleConstants.ALIGN_LEFT);
		} else {
			int value = (Integer) styleValuesTable
					.get(StyleConstants.Alignment);
			Integer value2 = (Integer) set
					.getAttribute(StyleConstants.Alignment);

			/* update alignment with new value */
			if (value2 != null) {
				if (value != value2.intValue()) {
					styleValuesTable.remove(StyleConstants.Alignment);
					styleValuesTable.put(StyleConstants.Alignment,
							value2.intValue());
				}
			}
		}

		if (styleValuesTable.get(StyleConstants.LineSpacing) == null) {
			styleValuesTable.put(StyleConstants.LineSpacing,
					LineSpacingButtonGroup.SingleSpace.SINGLE_SPACING);
		} else {
			float value = (Float) styleValuesTable
					.get(StyleConstants.LineSpacing);
			Float value2 = (Float) set.getAttribute(StyleConstants.LineSpacing);

			/* update line spacing with new value */
			if (value2 != null) {
				if (value != value2.floatValue()) {
					styleValuesTable.remove(StyleConstants.LineSpacing);
					styleValuesTable.put(StyleConstants.LineSpacing,
							value2.floatValue());
				}
			} else if (value2 == null) {
				styleValuesTable.put(StyleConstants.LineSpacing,
						LineSpacingButtonGroup.SingleSpace.SINGLE_SPACING);
			}
		}

		if (styleValuesTable.get(StyleConstants.Foreground) == null) {
			Color newColor = ForegroundColorButton.DEFAULT_FOREGROUND_COLOR;
			styleValuesTable.put(StyleConstants.Foreground, newColor);
		} else {
			Color fgcolor = (Color) set.getAttribute(StyleConstants.Foreground);
			if (fgcolor != null) {
				Color oldfgcolor = (Color) this.styleValuesTable
						.get(StyleConstants.Foreground);
				if (oldfgcolor != fgcolor) {
					styleValuesTable.remove(StyleConstants.Foreground);
					styleValuesTable.put(StyleConstants.Foreground, fgcolor);
				} else {
					if (styleValuesTable.get(StyleConstants.Foreground) == null) {
						Color newColor = ForegroundColorButton.DEFAULT_FOREGROUND_COLOR;
						styleValuesTable.put(StyleConstants.Foreground,
								newColor);
					}
				}
			}

			if (fgcolor == null) { // Set foreground color to default value
				fgcolor = ForegroundColorButton.DEFAULT_FOREGROUND_COLOR;
				styleValuesTable.remove(StyleConstants.Foreground);
				styleValuesTable.put(StyleConstants.Foreground, fgcolor);
			}
		}

		if (styleValuesTable.get(StyleConstants.Background) == null) {
			Color newColor = BackgroundColorButton.DEFAULT_BACKGROUND_COLOR;
			styleValuesTable.put(StyleConstants.Background, newColor);
		} else {
			Color bgcolor = (Color) set.getAttribute(StyleConstants.Background);
			if (bgcolor != null) {
				Color oldbgcolor = (Color) this.styleValuesTable
						.get(StyleConstants.Background);
				if (oldbgcolor != bgcolor) {
					styleValuesTable.remove(StyleConstants.Background);
					styleValuesTable.put(StyleConstants.Background, bgcolor);
				} else {
					if (styleValuesTable.get(StyleConstants.Background) == null) {
						Color newColor = BackgroundColorButton.DEFAULT_BACKGROUND_COLOR;
						styleValuesTable.put(StyleConstants.Background,
								newColor);
					}
				}
			}

			if (bgcolor == null) { // Set background color to default value
				bgcolor = BackgroundColorButton.DEFAULT_BACKGROUND_COLOR;
				styleValuesTable.remove(StyleConstants.Background);
				styleValuesTable.put(StyleConstants.Background, bgcolor);
			}
		}
	}

	/**
	 * Update the UI with the attribute values from the current paragraph where
	 * the caret is currently placed
	 * 
	 * @param paraElem
	 *            , the paragraph element
	 */
	public void setParagraphStyle(Element paraElem) {
		if (paraElem == null) {
			return;
		}

		updateParagraphStyleValues(paraElem);

		/*
		 * Send the list of UI changes to the UIupdater so that the changes
		 * become visible in the tool panel buttons
		 */
		UIupdate.update2(styleValuesTable);
	}

	private void updateParagraphStyleValues(Element e) {
		AttributeSet set = e.getAttributes();

		/*
		 * Get all properties and their corresponding current values and update
		 * the style values table
		 */
		if (styleValuesTable.contains(ExtendedDocument.PARAGRAPH_LEFT_INDENT)) {
			int value = (Integer) styleValuesTable
					.get(ExtendedDocument.PARAGRAPH_LEFT_INDENT);
			int value2 = (Integer) set
					.getAttribute(ExtendedDocument.PARAGRAPH_LEFT_INDENT);
			if (value != value2) {

				/* remove old attributes and insert new ones in style table */
				styleValuesTable.remove(ExtendedDocument.PARAGRAPH_LEFT_INDENT);
				styleValuesTable.put(ExtendedDocument.PARAGRAPH_LEFT_INDENT,
						value2);
			}
		} else {
			Integer value = (Integer) set
					.getAttribute(ExtendedDocument.PARAGRAPH_LEFT_INDENT);
			if (value == null) {
				value = CustomSlider.SLIDER_INITIAL_POSITION;
			}
			styleValuesTable.put(ExtendedDocument.PARAGRAPH_LEFT_INDENT, value);
		}
	}
}
